package com.xy6.jvm.fork.test;

import java.io.IOException;
import java.nio.file.DirectoryStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.RecursiveTask;
import java.util.concurrent.TimeUnit;

/**
 * 异步执行任务，本例的功能是查找硬盘上某一类型的文件
 * 
 * <pre>
 * 给定文件扩展名后，将硬盘上所有该类型的文件名打印显示出来。
 * 作为主程序，启动任务后，继续显示任务的执行进度，每3秒钟打印显示一个黑点，表示任务在继续。
 * 最后，当所有线程都结束了，打印显示结果。
 * </pre>
 * 
 * @author dell
 *
 */
public class SearchFileTask extends RecursiveTask<List<Path>> {

	private static final long serialVersionUID = 5973528259608587485L;

	private Path path;
	private String fileExtension;

	public SearchFileTask(Path path, String fileExtension) {
		super();
		this.path = path;
		this.fileExtension = fileExtension;
	}

	@Override
	protected List<Path> compute() {
		List<Path> result = new ArrayList<>();
		try {
			DirectoryStream<Path> paths = Files.newDirectoryStream(path);
			List<SearchFileTask> subTasks = new ArrayList<>();
			for (Path p : paths) {
				if (Files.isDirectory(p)) {
					SearchFileTask t = new SearchFileTask(p, fileExtension);
					t.fork();
					subTasks.add(t);
				} else if (Files.isRegularFile(p)) {
					if (p.toString().toLowerCase().endsWith("." + fileExtension)) {
						result.add(p);
					}
				}
			}

			for (SearchFileTask t : subTasks) {
				result.addAll(t.join());
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

		return result;
	}

	public static void main(String[] args) {
		DirectoryStream<Path> paths = null;
		try {
			String dir = "E:/1-文档/5-教材/";
			Path path = Paths.get(dir);
			paths = Files.newDirectoryStream(path);
			ForkJoinPool pool = new ForkJoinPool();
			List<SearchFileTask> tasks = new ArrayList<>();
			for (Path p : paths) {
				if (!Files.isDirectory(p)) {
					continue;
				}
				SearchFileTask t = new SearchFileTask(p, "pdf");
				pool.execute(t);
				tasks.add(t);
			}

			System.out.println("searching");
			while (isAllDone(tasks) == false) {
				System.out.println(". ");
				TimeUnit.SECONDS.sleep(2);
			}

			List<Path> result = new ArrayList<>();
			for (SearchFileTask t : tasks) {
				result.addAll(t.get());
			}

			for (Path p : result) {
				System.out.println(p);
			}

		} catch (IOException e) {
			e.printStackTrace();
		} catch (InterruptedException e) {
			e.printStackTrace();
		} catch (ExecutionException e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != paths) {
					paths.close();
				}
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	private static boolean isAllDone(List<SearchFileTask> tasks) {
		boolean result = true;
		for (SearchFileTask t : tasks) {
			if (t.isDone() == false) {
				result = false;
				break;
			}
		}
		return result;
	}

}
